/**  
 * Copyright (c) 2009, Noel Lynch All rights reserved. Redistribution and use  
 * in source and binary forms, with or without modification, are permitted  
 * provided that the following conditions are met: Redistributions of source  
 * code must retain the above copyright notice, this list of conditions and the  
 * following disclaimer. Redistributions in binary form must reproduce the above  
 * copyright notice, this list of conditions and the following disclaimer in the  
 * documentation and/or other materials provided with the distribution. Neither  
 * the name of Noel Lynch nor the names of contributors may be used to  
 * endorse or promote products derived from this software without specific prior  
 * written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 */
// created by noellynch
// Jun 24, 2009

package com.sceneworker.editors.texturepainter;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;

import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.math.Vector2f;
import com.jme2utils.objects.ITextureAndImageCallbacks;
import com.myjavautils.swing.DrawUtils;
import com.sceneworker.editors.texturepainter.TextureBufferedImageRep.ImageMode;
import com.sceneworker.editors.texturepainter.TextureBufferedImageRep.MixType;
import com.sceneworker.editors.texturepainter.brushgenerator.BrushImage;

public class TextureImagePaintableComponent extends JComponent {

	private		TextureBufferedImageRep				mcl_texRep;
	private		TextureBufferedImageRep.ImageMode	mcl_displayMode = ImageMode.rgba;
	private		BrushImage							mcl_brush;
	private		MixType								mcl_mixType = MixType.add;
	private		Point								mcl_lastPoint = new Point();
	private		float								mfa_colors[] = { 1.0f, 1.0f, 1.0f };
	
	private		int									mi_zoom = 1;
	
	public	TextureImagePaintableComponent() {
		addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				super.mousePressed(e);
			}

			@Override
			public void mouseReleased(MouseEvent e) {				
			}

			@Override
			public void mouseClicked(MouseEvent e) {
				paintMouse(e.getPoint());
			}

			@Override
			public void mouseEntered(MouseEvent e) {
				mcl_lastPoint = e.getPoint();
				repaint();
			}

			@Override
			public void mouseExited(MouseEvent e) {
				mcl_lastPoint = null;
				repaint();
			}
		});
		
		addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseDragged(MouseEvent e) {
				mcl_lastPoint = e.getPoint();
				paintMouse(e.getPoint());
			}

			@Override
			public void mouseMoved(MouseEvent e) {
				mcl_lastPoint = e.getPoint();
				repaint();
			}
			
		});
	}
	
	public	TextureImagePaintableComponent(BrushImage cl_brush) {
		this();
		mcl_brush = cl_brush;
	}
	
	public	TextureImagePaintableComponent(Image cl_image, Texture cl_texture, BrushImage cl_brush) {
		this();
		updateData(cl_image, cl_texture, cl_brush);
	}
	
	public	TextureImagePaintableComponent(TextureBufferedImageRep cl_rep, BrushImage cl_brush) {
		this();
		updateData(cl_rep, cl_brush);
	}
	
	public	void	updateData(Texture cl_texture) {
		if(cl_texture.getImage() == null) { return; }
		
		updateData(cl_texture.getImage(), cl_texture, mcl_brush);
	}
	
	public	TextureBufferedImageRep		getTextureRep() {
		return mcl_texRep;
	}
	
	public	void	updateData(Image cl_image, Texture cl_texture, BrushImage cl_brush) {
		mcl_texRep = new TextureBufferedImageRep(cl_texture, cl_image.getWidth(), cl_image.getHeight());
		mcl_brush = cl_brush;
		initialise();
	}
	
	public	void	updateData(TextureBufferedImageRep cl_rep, BrushImage cl_brush) {
		mcl_texRep = cl_rep;
		mcl_brush = cl_brush;
		initialise();
	}
	
	public	void	updateData(TextureBufferedImageRep cl_rep) {
		mcl_texRep = cl_rep;
		initialise();
	}
	
	private	void	initialise() {
		final	JComponent		lcl_this = this;
		mcl_texRep.addCallbackListener(new ITextureAndImageCallbacks() {
			public	void	loadTextureDataComplete() {
				lcl_this.repaint();
			}
			
			public	void	updateTextureDataComplete() {
				lcl_this.repaint();
			}
		});
	}
	
	/**
	 * Values from java awt color (0-255)
	 * @param i_r
	 * @param i_g
	 * @param i_b
	 */
	public	void	setPaintColours(int i_r, int i_g, int i_b) {
		mfa_colors[0] = (float)i_r / 255f;
		mfa_colors[1] = (float)i_g / 255f;
		mfa_colors[2] = (float)i_b / 255f;
	}
	
	public	void	setZoom(int i_zoom) {
		mi_zoom = i_zoom;
		repaint();
	}
	
	public	void	setMixType(MixType cl_mixType) {
		mcl_mixType = cl_mixType;
	}

	public	void	setImageDisplayMode(ImageMode cl_mode) {
		mcl_displayMode = cl_mode;
		repaint();
	}
	
	public	void	paintMouse(final Vector2f cl_uvCoord) {
		Point		lcl_pt = new Point();
		BufferedImage		lcl_image = mcl_texRep.getJavaRep(mcl_displayMode);
		int		li_imageX = (int)(cl_uvCoord.x * (float)lcl_image.getWidth());
		int		li_imageY = (int)(cl_uvCoord.y * (float)lcl_image.getHeight());
		
		if(mcl_displayMode == ImageMode.alpha) {
			mcl_texRep.mixAlpha(li_imageX - mcl_brush.getBrushRadius(), li_imageY - mcl_brush.getBrushRadius(), mcl_brush.getIntensityValues(), mcl_brush.getBrushRadius() << 1, mcl_mixType);
		} else {
			mcl_texRep.mixRGB(li_imageX - mcl_brush.getBrushRadius(), li_imageY - mcl_brush.getBrushRadius(), mcl_brush.getIntensityValues(), 
					mcl_brush.getBrushRadius() << 1, mcl_mixType, mfa_colors[0], mfa_colors[1], mfa_colors[2]);
		}
		
		repaint();
	}
	
	public	void	paintMouse(final Point cl_ptComponent) {
		BufferedImage		lcl_image = mcl_texRep.getJavaRep(mcl_displayMode);
		int		li_imageX = cl_ptComponent.x  - ((getWidth() - (lcl_image.getWidth() * mi_zoom)) >> 1);
		int		li_imageY = (lcl_image.getHeight() * mi_zoom) - (cl_ptComponent.y - ((getHeight() - (lcl_image.getHeight() * mi_zoom)) >> 1));
		
		//System.out.println(String.format("%d %d AFTER %d, %d", li_imageX, li_imageY, li_imageX / mi_zoom, li_imageY / mi_zoom));
		
		li_imageX /= mi_zoom;
		li_imageY /= mi_zoom;
		
		if(mcl_displayMode == ImageMode.alpha) {
			mcl_texRep.mixAlpha(li_imageX - mcl_brush.getBrushRadius(), li_imageY - mcl_brush.getBrushRadius(), mcl_brush.getIntensityValues(), mcl_brush.getBrushRadius() << 1, mcl_mixType);
		} else {
			mcl_texRep.mixRGB(li_imageX - mcl_brush.getBrushRadius(), li_imageY - mcl_brush.getBrushRadius(), mcl_brush.getIntensityValues(), 
					mcl_brush.getBrushRadius() << 1, mcl_mixType, mfa_colors[0], mfa_colors[1], mfa_colors[2]);
		}
		
		repaint();
	}
	
	@Override
	protected	void	paintComponent(Graphics cl_g) {
		Graphics2D		lcl_g = (Graphics2D)cl_g.create();
		lcl_g.setColor(Color.cyan);
		DrawUtils.fillComponentRect(lcl_g, this);
		AffineTransform		lcl_curTx = lcl_g.getTransform();
		lcl_g.scale(1, -1);

		if(mcl_texRep == null) {
			lcl_g.dispose();
			return;
		}
		
		BufferedImage		lcl_image = mcl_texRep.getJavaRep(mcl_displayMode);
		
		int		li_w = lcl_image.getWidth() * mi_zoom;
		int		li_h = lcl_image.getHeight() * mi_zoom;
		
		lcl_g.drawImage(lcl_image, (getWidth() >> 1) - (li_w >> 1), 
				-((getHeight() >> 1) + (li_h >> 1)), 
				li_w, li_h, this);
		
		lcl_g.setTransform(lcl_curTx);
		lcl_g.setColor(Color.black);
		
		if((mcl_brush != null) && (mcl_lastPoint != null)) {
			DrawUtils.drawPoint(lcl_g, mcl_lastPoint, mcl_brush.getBrushRadius() * mi_zoom);
		}
		
		lcl_g.dispose();
	}
	
	@Override
	public Dimension getMinimumSize() {
		if(mcl_texRep != null) {
			if(mcl_texRep.getJavaRep(mcl_displayMode) != null) {
				return new Dimension(mcl_texRep.getJavaRep(mcl_displayMode).getWidth(), mcl_texRep.getJavaRep(mcl_displayMode).getHeight());
			}
		}
		
		return new Dimension(100, 100);
	}
	
	@Override
	public Dimension getMaximumSize() {
		return getMinimumSize();
	}

	@Override
	public Dimension getPreferredSize() {
		return getMinimumSize();
	}
	
		
}
